/**
 * 
 */
package ro.dta.idbi.ui;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.List;

import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import ro.dta.idbi.interfaces.ApplicationSections;
import ro.dta.idbi.interfaces.ui.IMainFrame;
import ro.dta.idbi.interfaces.ui.IRepositoryBrowser;
import uk.ac.ic.doc.automed.IntegrityException;
import uk.ac.ic.doc.automed.NotFoundException;
import uk.ac.ic.doc.automed.STR;
import uk.ac.ic.doc.automed.reps.Schema;

/**
 * Repository Browser Panel used to display the contents of the AutoMed
 * repository
 * 
 * @author Tudor Dobrila
 */
public class RepositoryBrowserPanel extends JPanel implements IRepositoryBrowser, ActionListener {

	private static final long serialVersionUID = 4463821676747280620L;

	/**
	 * Icons used in the popup menu
	 */
	private static ImageIcon viewIcon, removeIcon, renameIcon;

	/**
	 * Initialise icons used in the popup menu
	 */
	static {
		viewIcon = new ImageIcon("./resources/explorer.png");
		removeIcon = new ImageIcon("./resources/delete_database.png");
		renameIcon = new ImageIcon("./resources/pen.png");
	}

	/**
	 * Popup menu shown when right clicking a schema
	 */
	private final transient JPopupMenu listPopup;

	/**
	 * Schemas list
	 */
	private final transient JList<String> schemasList;

	/**
	 * Model of the schemas list
	 */
	private final transient DefaultListModel<String> schemasModel;

	/**
	 * Model of the schemas list
	 */
	private final transient DefaultListModel<String> displayedModel;

	/**
	 * Parent frame of the application
	 */
	protected transient IMainFrame parentFrame;

	/**
	 * True if all schemas should be shown, false if only end of pathway schemas
	 * should be shown
	 */
	protected transient boolean showAll = true;

	/**
	 * Text field used to filter the results shown in the repository browser
	 */
	protected transient JTextField filterField;

	/**
	 * RepositoryBrowserPanel class constructor
	 * 
	 * @param parentFrame
	 *            Parent frame of the application
	 */
	public RepositoryBrowserPanel(final IMainFrame parentFrame) {
		super();
		this.parentFrame = parentFrame;
		setLayout(new GridBagLayout());

		final GridBagConstraints constr = new GridBagConstraints();
		constr.fill = GridBagConstraints.BOTH;

		final JTitleLabel titleLabel = new JTitleLabel("Repository Browser");
		constr.gridwidth = 2;
		constr.ipady = 15;
		constr.weightx = 1.0;
		constr.weighty = 0.0;
		constr.gridx = 0;
		constr.gridy = 0;
		add(titleLabel, constr);

		constr.gridwidth = 1;
		constr.ipady = 0;
		constr.weightx = 0.0;
		constr.weighty = 0.0;
		constr.gridx = 0;
		constr.gridy = 1;
		constr.insets = new Insets(3, 3, 3, 3);
		add(new JLabel("Filter:"), constr);
		
		constr.gridwidth = 1;
		constr.weightx = 1.0;
		constr.weighty = 0.0;
		constr.gridx = 1;
		constr.gridy = 1;
		filterField = new JTextField();
		filterField.getDocument().addDocumentListener(new DocumentListener() {
			
			@Override
			public void removeUpdate(DocumentEvent e) {
				filterResults();
			}
			
			@Override
			public void insertUpdate(DocumentEvent e) {
				filterResults();
			}
			
			@Override
			public void changedUpdate(DocumentEvent e) {
				filterResults();
			}
		});
		add(filterField, constr);
		
		listPopup = createPopupMenu();

		displayedModel = new DefaultListModel<String>();
		schemasModel = new DefaultListModel<String>();
		schemasList = new JList<String>(displayedModel);
		schemasList.setAutoscrolls(true);
		schemasList.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(final MouseEvent event) {
				if (schemasList.getSelectedIndices().length <= 1) {
					final int selectedIndex = schemasList.locationToIndex(event.getPoint());
					schemasList.setSelectedIndex(selectedIndex);
				}
				if (SwingUtilities.isRightMouseButton(event)) {
					listPopup.show(schemasList, event.getX(), event.getY());
				}

				if (SwingUtilities.isLeftMouseButton(event) && event.getClickCount() == 2) {
					final Object lastItem = schemasList.getSelectedValue();
					openSchema(lastItem);
				}
			}
		});
		showAllSchemas(true);

		final JScrollPane scrollPane = new JScrollPane(schemasList);
		constr.insets = new Insets(0, 0, 0, 0);
		constr.gridwidth = 2;
		constr.ipady = 0;
		constr.weightx = 1.0;
		constr.weighty = 1.0;
		constr.gridx = 0;
		constr.gridy = 2;
		add(scrollPane, constr);

		parentFrame.setStatusBarText("AutoMed repository loaded");
	}

	@Override
	public void actionPerformed(final ActionEvent event) {
		final JMenuItem sourceItem = (JMenuItem) event.getSource();
		final List<String> selectedItems = schemasList.getSelectedValuesList();

		if (sourceItem.getName().equals("view")) {
			// View schema
			final Object lastItem = selectedItems.get(selectedItems.size() - 1);
			openSchema(lastItem);
		}

		if (sourceItem.getName().equals("rename")) {
			// Rename schema
			String result = JOptionPane.showInputDialog(null,
					"Please enter the new name of the schema", "Enter new name",
					JOptionPane.QUESTION_MESSAGE);
			if (result != null) {
				final Object lastItem = selectedItems.get(selectedItems.size() - 1);
				try {
					Schema schema = Schema.getSchema(lastItem.toString());
					schema.setName(result);
					parentFrame.getRepositoryBrowser().refresh();
					parentFrame.getRepositoryBrowser().select(result);
					parentFrame.setStatusBarText("Schema has been successfully rename.");
				} catch (NotFoundException e) {
					JOptionPane.showMessageDialog(null, "Schema " + lastItem.toString()
							+ " does not exist in the AutoMed repository.", "Error!",
							JOptionPane.ERROR_MESSAGE);
				} catch (IntegrityException e) {
					JOptionPane.showMessageDialog(null, "Schema " + result
							+ " already exists in the AutoMed repository. Renaming failed.",
							"Error!", JOptionPane.ERROR_MESSAGE);
				}
			}
		}

		if ((sourceItem.getName().equals("remove") || sourceItem.getName().equals("retract"))
				&& selectedItems.size() > 0
				&& JOptionPane.showConfirmDialog(this,
						"Are you sure you want to " + sourceItem.getName()
								+ " the schema(s) from the AutoMed repository?", "Confirm",
						JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
			// Remove / retract schema(s)
			boolean isOk = true;
			for (String schema : selectedItems) {
				if (Schema.exists(schema)) {
					try {
						if (sourceItem.getName().equals("remove")) {
							Schema.remove(schema);
						} else {
							Schema.getSchema(schema).oldRetract();
						}
					} catch (Exception e1) {
						isOk = false;
						JOptionPane.showMessageDialog(this, "Could not remove schema " + schema
								+ ".\r\nReason: " + e1.getMessage(), "Error",
								JOptionPane.ERROR_MESSAGE);
					}
				} else {
					isOk = false;
					JOptionPane.showMessageDialog(this, "Schema " + schema
							+ " does not exist in the repository", "Error",
							JOptionPane.ERROR_MESSAGE);
				}
			}

			parentFrame.getRepositoryBrowser().refresh();
			if (isOk) {
				parentFrame.setStatusBarText("Schema(s) has/have been successfully removed.");
				JOptionPane.showMessageDialog(null,
						"Schema(s) has/have been successfully removed.", "Success",
						JOptionPane.INFORMATION_MESSAGE);
			}
		}
	}

	@Override
	public void refresh() {
		showAllSchemas(showAll);
	}

	@Override
	public void select(final String item) {
		schemasList.setSelectedValue(item, true);

	}

	@Override
	public void showAllSchemas(boolean showAll) {
		this.showAll = showAll;
		final Schema[] schemas = Schema.getSchemas();
		schemasModel.removeAllElements();

		for (Schema s : schemas) {
			boolean endPathway = false;
			int[] toSchemas;
			try {
				toSchemas = STR.getTranToSchema(s.getSID());
				if (toSchemas.length == 0) {
					endPathway = true;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}

			if (showAll || (!showAll && endPathway)) {
				schemasModel.addElement(s.getName());
			}
		}
		
		filterResults();
	}

	/**
	 * Filter the results displayed according to the value of <i>filterField</i><br />
	 * Display only those schemas that start with <i>filterField.getText()</i>
	 */
	public void filterResults() {
		String filter = filterField.getText();
		displayedModel.removeAllElements();

		int elCount = schemasModel.size();
		for (int i = 0; i < elCount; i++) {
			String crtItem = schemasModel.get(i);
			if ("".equals(filter) || (!"".equals(filter) && crtItem.startsWith(filter))) {
				displayedModel.addElement(crtItem);
			}
		}
	}

	/**
	 * Create the popup menu used to perform operations over schemas
	 * 
	 * @return Popup menu used to perform operations over schemas
	 */
	private JPopupMenu createPopupMenu() {
		final JPopupMenu listPopup = new JPopupMenu();

		final JMenuItem viewItem = new JMenuItem("View diagram");
		viewItem.setIcon(viewIcon);
		viewItem.setName("view");
		viewItem.addActionListener(this);
		listPopup.add(viewItem);

		final JMenuItem renameItem = new JMenuItem("Rename");
		renameItem.setIcon(renameIcon);
		renameItem.setName("rename");
		renameItem.addActionListener(this);
		listPopup.add(renameItem);

		final JMenuItem removeItem = new JMenuItem("Remove");
		removeItem.setIcon(removeIcon);
		removeItem.setName("remove");
		removeItem.addActionListener(this);
		listPopup.add(removeItem);

		final JMenuItem retractItem = new JMenuItem("Retract");
		retractItem.setIcon(removeIcon);
		retractItem.setName("retract");
		retractItem.addActionListener(this);
		listPopup.add(retractItem);

		return listPopup;
	}

	/**
	 * Open the schema with the name passed as parameter
	 * 
	 * @param lastItem
	 *            Name of the schema to open in the right panel
	 */
	private void openSchema(Object lastItem) {
		if (lastItem != null) {
			parentFrame.open(ApplicationSections.VIEW_SQL_SCHEMA, new Object[] { lastItem },
					lastItem.toString(), new ImageIcon("./resources/schema.png"), "View schema: "
							+ lastItem, "Loaded schema " + lastItem
							+ " from the AutoMed repository");
		}
	}
}
